package com.chongchong.online.controller;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chongchong.online.wrapper.OnlinePageWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.chongchong.common.constant.ErrorCodeEnum;
import com.chongchong.common.tool.CommonUtil;
import com.chongchong.common.validator.UpdateGroup;
import com.chongchong.core.mp.object.MyModelUtil;
import com.chongchong.core.mp.object.MyRelationParam;
import com.chongchong.core.mp.support.Condition;
import com.chongchong.core.mp.support.Query;
import com.chongchong.core.tool.api.R;
import com.chongchong.core.tool.utils.Func;
import com.chongchong.online.dto.OnlinePageDatasourceDto;
import com.chongchong.online.dto.OnlinePageDto;
import com.chongchong.online.entity.OnlineDatasource;
import com.chongchong.online.entity.OnlinePage;
import com.chongchong.online.entity.OnlinePageDatasource;
import com.chongchong.online.entity.constant.PageStatus;
import com.chongchong.online.service.IOnlineDatasourceService;
import com.chongchong.online.service.IOnlineFormService;
import com.chongchong.online.service.IOnlinePageService;
import com.chongchong.online.vo.OnlineDatasourceVo;
import com.chongchong.online.vo.OnlinePageDatasourceVo;
import com.chongchong.online.vo.OnlinePageVo;
import com.chongchong.online.wrapper.OnlineDatasourceWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.validation.groups.Default;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 在线表单页面操作控制器类。
 *
 * @author Jerry
 * @date 2021-06-06
 */
@Api(tags = "在线表单页面操作接口")
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/onlinepage")
public class OnlinePageController {

    private IOnlinePageService onlinePageService;
    private IOnlineFormService onlineFormService;
    private IOnlineDatasourceService onlineDatasourceService;

    /**
     * 新增在线表单页面数据。
     *
     * @param onlinePageDto 新增对象。
     * @return 应答结果对象，包含新增对象主键Id。
     */
    @ApiOperationSupport(ignoreParameters = {"onlinePageDto.pageId"})
    @PostMapping("/save")
    public R<Long> add(@RequestBody OnlinePageDto onlinePageDto) {
        String errorMessage = CommonUtil.getModelValidationError(onlinePageDto);
        if (errorMessage != null) {
            return R.fail(errorMessage);
        }
        OnlinePage onlinePage = MyModelUtil.copyTo(onlinePageDto, OnlinePage.class);
        onlinePage = onlinePageService.saveNew(onlinePage);
        return R.data(onlinePage.getPageId());
    }

    /**
     * 更新在线表单页面数据。
     *
     * @param onlinePageDto 更新对象。
     * @return 应答结果对象。
     */
    @PostMapping("/update")
    public R<Void> update(@RequestBody OnlinePageDto onlinePageDto) {
        String errorMessage = CommonUtil.getModelValidationError(onlinePageDto, Default.class, UpdateGroup.class);
        if (errorMessage != null) {
			return R.fail(errorMessage);
        }
        OnlinePage onlinePage = MyModelUtil.copyTo(onlinePageDto, OnlinePage.class);
        OnlinePage originalOnlinePage = onlinePageService.getById(onlinePage.getPageId());
        if (originalOnlinePage == null) {
            errorMessage = "数据验证失败，当前页面对象并不存在，请刷新后重试！";
			return R.fail(errorMessage);
        }
        if (!onlinePage.getPageType().equals(originalOnlinePage.getPageType())) {
            errorMessage = "数据验证失败，页面类型不能修改！";
			return R.fail(errorMessage);
        }
        if (!onlinePageService.update(onlinePage, originalOnlinePage)) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        return R.data(null);
    }

    /**
     * 更新在线表单页面对象的发布状态字段。
     *
     * @param pageId    待更新的页面对象主键Id。
     * @param published 发布状态。
     * @return 应答结果对象。
     */
    @PostMapping("/updatePublished")
    public R<Void> updateStatus(
            @RequestParam(required = true) Long pageId,
            @RequestParam(required = true) Boolean published) {
        String errorMessage;
        // 验证关联Id的数据合法性
        OnlinePage originalOnlinePage = onlinePageService.getById(pageId);
        if (originalOnlinePage == null) {
            errorMessage = "数据验证失败，当前页面对象并不存在，请刷新后重试！";
			return R.fail(errorMessage);
        }
        if (!published.equals(originalOnlinePage.getPublished())) {
            if (published && !originalOnlinePage.getStatus().equals(PageStatus.FORM_DESIGN)) {
                errorMessage = "数据验证失败，当前页面状态不为 [设计] 状态，因此不能发布！";
				return R.fail(errorMessage);
            }
            onlinePageService.updatePublished(pageId, published);
        }
        return R.data(null);
    }

    /**
     * 删除在线表单页面数据。
     *
     * @param pageId 删除对象主键Id。
     * @return 应答结果对象。
     */
    @PostMapping("/delete")
    public R<Void> delete(@RequestBody Long pageId) {
        String errorMessage;
        if (CommonUtil.existBlankArgument(pageId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        // 验证关联Id的数据合法性
        OnlinePage originalOnlinePage = onlinePageService.getById(pageId);
        if (originalOnlinePage == null) {
            errorMessage = "数据验证失败，当前页面对象并不存在，请刷新后重试！";
			return R.fail(errorMessage);
        }
        if (!onlinePageService.remove(pageId)) {
            errorMessage = "数据操作失败，删除的对象不存在，请刷新后重试！";
			return R.fail(errorMessage);
        }
        return R.data(null);
    }

	/**
	 * 删除
	 */
	@PostMapping("/remove")
	@ApiOperationSupport(order = 7)
	@ApiOperation(value = "逻辑删除", notes = "传入ids")
	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
		return R.status(onlinePageService.removeByIds(Func.toLongList(ids)));
	}


	/**
     * 列出符合过滤条件的在线表单页面列表。
     *
     * @param onlinePage 过滤对象。
     * @param query           分页参数。
     * @return 应答结果对象，包含查询结果集。
     */
    @GetMapping("/list")
	@ApiOperation(value = "分页", notes = "传入onlineDict")
	public R<IPage<OnlinePageVo>> list(OnlinePage onlinePage, Query query) {
//		OnlinePage onlinePageFilter = MyModelUtil.copyTo(onlinePageDtoFilter, OnlinePage.class);
//		String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlinePage.class);
//		List<OnlinePage> onlinePageList = onlinePageService.getOnlinePageListWithRelation(onlinePageFilter, orderBy);

		IPage<OnlinePage> pages = onlinePageService.page(Condition.getPage(query), Condition.getQueryWrapper(onlinePage));

		return R.data(OnlinePageWrapper.build().pageVO(pages));
	}

	/**
	 * 列出符合过滤条件的在线表单页面列表。
	 *
	 * @param onlinePage 过滤对象。
	 * @return 应答结果对象，包含查询结果集。
	 */
	@GetMapping("/listNoPage")
	@ApiOperation(value = "不分页", notes = "传入onlineDict")
	public R<List<OnlinePageVo>> listNoPage(OnlinePage onlinePage) {
		List<OnlinePage> list = onlinePageService.list(Condition.getQueryWrapper(onlinePage));

		return R.data(OnlinePageWrapper.build().listVO(list));
	}

    /**
     * 获取系统中配置的所有Page和表单的列表。
     *
     * @return 系统中配置的所有Page和表单的列表。
     */
	@GetMapping("/listAllPageAndForm")
    public R<JSONObject> listAllPageAndForm() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("pageList", onlinePageService.list());
        jsonObject.put("formList", onlineFormService.list());
        return R.data(jsonObject);
    }

	/**
	 * 详情
	 */
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "详情", notes = "传入onlinePage")
	public R<OnlinePageVo> detail(OnlinePage onlinePage) {
		OnlinePage detail = onlinePageService.getOne(Condition.getQueryWrapper(onlinePage));
		return R.data(OnlinePageWrapper.build().entityVO(detail));
	}

    /**
     * 查看指定在线表单页面对象详情。
     *
     * @param pageId 指定对象主键Id。
     * @return 应答结果对象，包含对象详情。
     */
    @GetMapping("/view")
    public R<OnlinePageVo> view(@RequestParam Long pageId) {
        if (CommonUtil.existBlankArgument(pageId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        OnlinePage onlinePage = onlinePageService.getByIdWithRelation(pageId, MyRelationParam.full());
        if (onlinePage == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        return R.data(OnlinePageWrapper.build().entityVO(onlinePage));
    }

    /**
     * 列出不与指定在线表单页面存在多对多关系的在线数据源列表数据。通常用于查看添加新在线数据源对象的候选列表。
     *
     * @param pageId                    主表关联字段。
     * @return 应答结果对象，返回符合条件的数据列表。
     */
	@GetMapping("/listNotInOnlinePageDatasource")
	public R<List<OnlineDatasourceVo>> listNotInOnlinePageDatasource(@RequestParam Long pageId) {
		R<Void> verifyResult = this.doOnlinePageDatasourceVerify(pageId);
		if (!verifyResult.isSuccess()) {
			return R.fail(verifyResult.getMsg());
		}
		List<OnlineDatasource> onlineDatasourceList =
			onlineDatasourceService.getNotInOnlineDatasourceListByPageId(pageId, new OnlineDatasource(), null);

//		IPage<OnlineDatasource> pages = new Page<>(query.getCurrent(), query.getSize());
//		pages.setRecords(onlineDatasourceList);

		return R.data(OnlineDatasourceWrapper.build().listVO(onlineDatasourceList));
	}

    /**
     * 列出与指定在线表单页面存在多对多关系的在线数据源列表数据。
     *
     * @param pageId                    主表关联字段。
     * @return 应答结果对象，返回符合条件的数据列表。
     */
	@GetMapping("/listOnlinePageDatasource")
	public R<List<OnlineDatasourceVo>> listOnlinePageDatasource(@RequestParam Long pageId) {
		R<Void> verifyResult = this.doOnlinePageDatasourceVerify(pageId);
		if (!verifyResult.isSuccess()) {
			return R.fail(verifyResult.getMsg());
		}
//		OnlineDatasource filter = MyModelUtil.copyTo(onlineDatasourceDtoFilter, OnlineDatasource.class);
//		String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineDatasource.class);
		List<OnlineDatasource> onlineDatasourceList =
			onlineDatasourceService.getOnlineDatasourceListByPageId(pageId, new OnlineDatasource(), null);

//		IPage<OnlineDatasource> pages = new Page<>(query.getCurrent(), query.getSize());
//		pages.setRecords(onlineDatasourceList);

		return R.data(OnlineDatasourceWrapper.build().listVO(onlineDatasourceList));
	}

    /**
     * 批量添加在线表单页面和在线数据源对象的多对多关联关系数据。
     *
     * @param pageId                      主表主键Id。
     * @param onlinePageDatasourceDtoList 关联对象列表。
     * @return 应答结果对象。
     */
    @PostMapping("/addOnlinePageDatasource")
    public R<Void> addOnlinePageDatasource(
            @RequestBody Long pageId,
            @RequestBody List<OnlinePageDatasourceDto> onlinePageDatasourceDtoList) {
        if (CommonUtil.existBlankArgument(pageId, onlinePageDatasourceDtoList)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        for (OnlinePageDatasourceDto onlinePageDatasource : onlinePageDatasourceDtoList) {
            String errorMessage = CommonUtil.getModelValidationError(onlinePageDatasource);
            if (errorMessage != null) {
                return R.fail(errorMessage);
            }
        }
        Set<Long> datasourceIdSet =
                onlinePageDatasourceDtoList.stream().map(OnlinePageDatasourceDto::getDatasourceId).collect(Collectors.toSet());
        if (onlinePageService.getById(pageId) == null
                || !onlineDatasourceService.existUniqueKeyList("datasourceId", datasourceIdSet)) {
            return R.fail(ErrorCodeEnum.INVALID_RELATED_RECORD_ID.getErrorMessage());
        }
        List<OnlinePageDatasource> onlinePageDatasourceList =
                MyModelUtil.copyCollectionTo(onlinePageDatasourceDtoList, OnlinePageDatasource.class);
        onlinePageService.addOnlinePageDatasourceList(onlinePageDatasourceList, pageId);
        return R.data(null);
    }

    /**
     * 显示在线表单页面和指定数据源的多对多关联详情数据。
     *
     * @param pageId       主表主键Id。
     * @param datasourceId 从表主键Id。
     * @return 应答结果对象，包括中间表详情。
     */
    @GetMapping("/viewOnlinePageDatasource")
    public R<OnlinePageDatasourceVo> viewOnlinePageDatasource(
		@RequestParam Long pageId, @RequestParam Long datasourceId) {
        if (CommonUtil.existBlankArgument(pageId, datasourceId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        OnlinePageDatasource onlinePageDatasource = onlinePageService.getOnlinePageDatasource(pageId, datasourceId);
        if (onlinePageDatasource == null) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        OnlinePageDatasourceVo onlinePageDatasourceVo = MyModelUtil.copyTo(onlinePageDatasource, OnlinePageDatasourceVo.class);
        return R.data(onlinePageDatasourceVo);
    }

    /**
     * 移除指定在线表单页面和指定数据源的多对多关联关系。
     *
     * @param pageId       主表主键Id。
     * @param datasourceId 从表主键Id。
     * @return 应答结果对象。
     */
    @PostMapping("/deleteOnlinePageDatasource")
    public R<Void> deleteOnlinePageDatasource(
		@RequestBody Long pageId, @RequestBody Long datasourceId) {
        if (CommonUtil.existBlankArgument(pageId, datasourceId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        if (!onlinePageService.removeOnlinePageDatasource(pageId, datasourceId)) {
            return R.fail(ErrorCodeEnum.DATA_NOT_EXIST.getErrorMessage());
        }
        return R.data(null);
    }

    private R<Void> doOnlinePageDatasourceVerify(Long pageId) {
        if (CommonUtil.existBlankArgument(pageId)) {
            return R.fail(ErrorCodeEnum.ARGUMENT_NULL_EXIST.getErrorMessage());
        }
        if (onlinePageService.getById(pageId) == null) {
            return R.fail(ErrorCodeEnum.INVALID_RELATED_RECORD_ID.getErrorMessage());
        }
        return R.data(null);
    }
}
